package com.slh.touchandroid.utils;

import java.io.FileNotFoundException;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.net.URLConnection;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.util.LruCache;
import android.widget.ImageView;

public class ImageUtils {
	private LruCache<String, Bitmap> lruCache;;
	private static ImageUtils imageUtils;

	// ====================================================================================
	public static synchronized ImageUtils getInstance() {
		if (imageUtils == null) {
			imageUtils = new ImageUtils();
			final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
			imageUtils.lruCache = new LruCache<String, Bitmap>(maxMemory) {
				@Override
				protected int sizeOf(String key, Bitmap bitmap) {
					return bitmap.getByteCount() / 1024;
				}
			};

		}
		return imageUtils;
	}

	private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
		if (getBitmapFromMemCache(key) == null) {
			lruCache.put(key, bitmap);
		}
	}

	private Bitmap getBitmapFromMemCache(String key) {
		return lruCache.get(key);
	}

	// ====================================================================================
	public static void loadImage(final Context context, ImageView imageView,
			int resId) {

		ImageLoader<Integer> imageLoader = new ImageLoader<Integer>(imageView) {
			@Override
			protected Bitmap doInBackground(Integer... params) {
				super.doInBackground(params);
				return BitmapFactory.decodeResource(context.getResources(),
						params[0]);
			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(resId);
	}

	public static void loadImage(final Context context, ImageView imageView,
			int resId, final int scaleWidth, final int scaleHieght) {

		ImageLoader<Integer> imageLoader = new ImageLoader<Integer>(imageView) {
			@Override
			protected Bitmap doInBackground(Integer... params) {
				super.doInBackground(params);
				Bitmap bitmap = BitmapFactory.decodeResource(
						context.getResources(), params[0]);
				return Bitmap.createScaledBitmap(bitmap, scaleWidth,
						scaleHieght, true);
			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(resId);
	}

	// ====================================================================================
	public static void loadImage(final Context context, ImageView imageView,
			Uri uri) {

		ImageLoader<Uri> imageLoader = new ImageLoader<Uri>(imageView) {
			@Override
			protected Bitmap doInBackground(Uri... params) {
				super.doInBackground(params);
				try {
					return BitmapFactory.decodeStream(context
							.getContentResolver().openInputStream(params[0]));
				} catch (FileNotFoundException e) {
					return null;
				}
			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(uri);
	}

	public static void loadImage(final Context context, ImageView imageView,
			Uri uri, final int scaleWidth, final int scaleHieght) {

		ImageLoader<Uri> imageLoader = new ImageLoader<Uri>(imageView) {
			@Override
			protected Bitmap doInBackground(Uri... params) {
				super.doInBackground(params);
				try {
					Bitmap bitmap = BitmapFactory.decodeStream(context
							.getContentResolver().openInputStream(params[0]));

					return Bitmap.createScaledBitmap(bitmap, scaleWidth,
							scaleHieght, true);
				} catch (FileNotFoundException e) {
					return null;
				}
			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(uri);

	}

	// ====================================================================================
	public static void loadImage(final Context context, ImageView imageView,
			String path) {

		ImageLoader<String> imageLoader = new ImageLoader<String>(imageView) {
			@Override
			protected Bitmap doInBackground(String... params) {
				super.doInBackground(params);
				return BitmapFactory.decodeFile((params[0]));
			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(path);

	}

	public static void loadImage(final Context context, ImageView imageView,
			String path, final int scaleWidth, final int scaleHieght) {

		ImageLoader<String> imageLoader = new ImageLoader<String>(imageView) {
			@Override
			protected Bitmap doInBackground(String... params) {
				super.doInBackground(params);
				Bitmap bitmap = BitmapFactory.decodeFile(params[0]);

				return Bitmap.createScaledBitmap(bitmap, scaleWidth,
						scaleHieght, true);
			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(path);

	}

	// ====================================================================================
	public void loadImageFromUrl(final Context context, ImageView imageView,
			String url) {

		ImageLoader<String> imageLoader = new ImageLoader<String>(imageView) {

			@Override
			protected Bitmap doInBackground(String... params) {
				super.doInBackground(params);
				Bitmap cache = getBitmapFromMemCache(params[0]);
				if (cache != null) {
					return cache;
				}
				try {
					URLConnection conn = new URL(params[0]).openConnection();
					conn.connect();
					Bitmap bitmap = BitmapFactory.decodeStream(conn
							.getInputStream());
					addBitmapToMemoryCache(params[0], bitmap);
					return bitmap;
				} catch (Exception e) {
					return null;
				}

			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(url);
	}

	public void loadImageFromUrl(final Context context, ImageView imageView,
			String url, final int scaleWidth, final int scaleHieght) {

		ImageLoader<String> imageLoader = new ImageLoader<String>(imageView) {

			@Override
			protected Bitmap doInBackground(String... params) {
				super.doInBackground(params);
				Bitmap cache = getBitmapFromMemCache(params[0]);
				if (cache != null) {
					return cache;
				}
				try {
					URLConnection conn = new URL(params[0]).openConnection();
					conn.connect();
					Bitmap bitmap = BitmapFactory.decodeStream(conn
							.getInputStream());
					bitmap = Bitmap.createScaledBitmap(bitmap, scaleWidth,
							scaleHieght, true);
					addBitmapToMemoryCache(params[0], bitmap);
					return bitmap;
				} catch (Exception e) {
					return null;
				}

			}
		};
		AsyncDrawable asyncDrawable = new AsyncDrawable(imageLoader);
		imageView.setImageDrawable(asyncDrawable);
		imageLoader.excuteAsync(url);
	}

	// ====================================================================================
	public static class AsyncDrawable extends BitmapDrawable {
		private final WeakReference<ImageLoader<?>> loaderReference;

		@SuppressWarnings("deprecation")
		public AsyncDrawable(ImageLoader<?> imageLoader) {
			super();
			this.loaderReference = new WeakReference<ImageLoader<?>>(
					imageLoader);
		}

		public ImageLoader<?> getImageLoader() {
			return loaderReference.get();
		}

	}

	// ====================================================================================

	public static class ImageLoader<Params> extends
			AsyncTask<Params, Void, Bitmap> {
		private final WeakReference<ImageView> imgReference;
		private Object object = null;

		public ImageLoader(ImageView imageView) {
			super();
			this.imgReference = new WeakReference<ImageView>(imageView);

		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}

		@Override
		protected Bitmap doInBackground(Params... params) {
			object = params[0];
			return null;
		}

		@Override
		protected void onPostExecute(Bitmap bitmap) {
			if (isCancelled()) {
				return;
			}

			if (imgReference != null && bitmap != null) {
				final ImageView imageView = imgReference.get();
				final ImageLoader<?> imageLoader = getImageLoader(imageView);
				if (this == imageLoader && imageView != null) {
					imageView.setImageBitmap(bitmap);
				}
			}
			super.onPostExecute(bitmap);
		}

		public void excuteAsync(Params... params) {
			if (Build.VERSION.SDK_INT < 11) {
				execute(params);
			} else {
				executeOnExecutor(THREAD_POOL_EXECUTOR, params);
			}
			
		}
	}

	// ====================================================================================
	private static ImageLoader<?> getImageLoader(ImageView imageView) {
		if (imageView != null) {
			final Drawable drawable = imageView.getDrawable();
			if (drawable instanceof AsyncDrawable) {
				final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
				return asyncDrawable.getImageLoader();
			}
		}
		return null;
	}

	public static boolean cancelPotentialWork(Object object, ImageView imageView) {
		final ImageLoader<?> imageLoader = getImageLoader(imageView);

		if (imageLoader != null) {
			final Object objectData = imageLoader.object;
			// If bitmapData is not yet set or it differs from the new data
			if (objectData == null || !objectData.equals(object)) {
				// Cancel previous task
				imageLoader.cancel(true);
			} else {
				// The same work is already in progress
				return false;
			}
		}
		// No task associated with the ImageView, or an existing task was
		// cancelled
		return true;
	}

}
